5.2.4 -
Les mécanismes
d’autorisation :
Le service d'autorisation décide d'autoriser ou non les actions
entreprises par des processus, en se basant sur les attributs d'autorisation
contenus dans le jeton de chaque processus.
Parmi les attributs
d'autorisation, les différents SID sont utilisés par le
contrôle d'accès, mécanisme qui permet de contrôler
quels acteurs principaux ont accès aux objets et de quelles
façons. Les privilèges sont eux utilisés lorsque
l'autorisation par contrôle d'accès n'est pas
adaptée.
5.2.4.A - Le contrôle
d’accès :
Le contrôle d'accès a lieu dans le contexte d'un processus
accédant à un objet. Pour un processus, l'accès à un
objet se fait toujours via une référence (handle), obtenue lors de
l'ouverture de l'objet, via les fonctions de l'API Win32 du type OpenXxx() et
CreateXxx(). Il est important de retenir que le contrôle d'accès,
de même que l'audit, ont lieu lors de l'ouverture d'un l'objet. Si le
contrôle d'accès valide l'ouverture d'un objet avec certaines
permissions, il n'y a ensuite plus de contrôle pour cet objet,
exceptés ceux s'assurant que l'objet est utilisé dans les limites
de ce qui a été autorisé lors de son ouverture.
Par
exemple, si au moment de l'ouverture en lecture seule d'un fichier par un
processus, le fichier était en lecture et écriture pour
l’acteur principal Administrateur, une tentative d'écriture dans le
fichier ne sera pas autorisée puisque le fichier a été
ouvert en lecture seule. Si le fichier est fermé puis ré-ouvert en
lecture-écriture, les deux types d'accès seront autorisés
tant que le fichier reste ouvert, même si, entre temps, le droit
d'écriture sur ce fichier est retiré à l’acteur
principal Administrateur.
Le contrôle d'accès fonctionne en
faisant le rapprochement entre trois éléments : les permissions
spécifiées lors de l'ouverture d'un objet, le descripteur de
sécurité de l'objet accédé et le jeton du processus
(attributs d'autorisation) réalisant l'accès.
5.2.4.B - La gestion des
permissions :
Lorsqu'un processus ouvre une référence à un objet, il
précise quels types d'accès il veut réaliser sur l'objet,
via un masque de permissions décrivant les permissions sur l'objet dont
il souhaite disposer. Si ces permissions sont compatibles avec le descripteur de
sécurité de l'objet, une référence à l'objet
est accordée, le système se contentant ensuite de vérifier
que les types d'accès font partie de ceux spécifiés lors de
l'ouverture de l'objet. Dans les fonctions de l'API Win32 du type OpenXxx() et
CreateXxx(), le masque de permissions est fourni dans le paramètre de nom
dwDesiredAccess.
Un masque de permissions est une valeur de 32 bits,
subdivisée en 4 : permissions standard (8 bits), permissions
spécifiques (16 bits), permissions génériques (4 bits) et
divers drapeaux (4 bits).
Les permissions standard sont des permissions
qui s'appliquent à tous les types d'objets. Cinq sont actuellement
définies :
- suppression de l'objet (DELETE) ;
- lecture du contenu du descripteur de sécurité de l'objet
(READ_CONTROL) ;
- changement du propriétaire de l'objet (WRITE_OWNER) ;
- changement de la liste de contrôle d'accès de l'objet
(WRITE_DAC) ;
- autorisation de se synchroniser sur cet objet
(SYNCHRONIZE).
Les permissions spécifiques ne
s'appliquent qu'à un type d'objet donné. Par exemple, pour un
objet du type processus, une permission, PROCESS_TERMINATE, est définie
pour autoriser la terminaison d'un processus.
Enfin, quatre permissions
génériques sont définies :
- lecture (GENERIC_READ);
- écriture (GENERIC_WRITE);
- exécution (GENERIC_EXECUTE) ;
- les trois à la fois (GENERIC_ALL).
Elles s'appliquent
à tous les types d'objets et permettent un polymorphisme des permissions,
chacune des 4 permissions génériques étant
équivalente à une liste de permissions standard et
spécifiques. Par exemple, la permission générique de
lecture (GENERIC_READ) sur un objet de type clé de la base de registres
accorde la permission standard READ_CONTROL et les trois permissions
spécifiques KEY_QUERY_VALUE, KEY_ENUMERATE_SUB_KEYS et KEY_NOTIFY. Cette
possibilité est intéressante pour le paramétrage des
permissions sur les nouveaux objets créés.
5.2.4.C - Descripteur de
sécurité :
A tout objet sécurisable est associé un descripteur de
sécurité (security descriptor, abrégé en SD), qui
contient trois informations principales :
- le SID du propriétaire de l'objet ;
- sa liste de contrôle d'accès discrétionnaire
(DACL) ;
- sa liste de contrôle d'accès système (SACL).
Tout objet a un propriétaire, dont le SID est
stocké dans le SD. Le propriétaire d'un objet a toujours le droit
de lire et de modifier la DACL des objets lui appartenant. C'est pour cette
raison que le contrôle d'accès est qualifié de
discrétionnaire, étant à la discrétion du
propriétaire.
La DACL est simplement une liste d'entrées
de contrôle d'accès (access control entry, abrégée en
ACE) listant quels accès sont possibles à quels SID. Ces SID
peuvent désigner des acteurs principaux uniques, des groupes locaux ou
globaux.
Une ACE peut être positive ou négative : si elle
est positive, elle accorde un type d'accès ; si elle est négative,
elle refuse un type d'accès. Le type d'accès est
spécifié sous la forme d'un masque de permissions.
5.2.4.D - Jeton de
sécurité :
Un jeton est attaché à un processus et définit son
contexte de sécurité. Son contenu se subdivise en trois
catégories :
- identité et attributs d'autorisation ;
- sécurité par défaut pour les nouveaux objets
créés ;
- divers paramètres.
Pour le contrôle
d'accès, les attributs d'autorisation utilisés sont les SID. Il y
a au moins le SID du propriétaire du processus puis la liste des SID des
groupes globaux (au niveau du domaine) et des groupes locaux (alias, au niveau
du système local) dont l’acteur principal fait partie. Sont
également présents un SID indiquant le type de session de
connexion (par exemple, interactive) ainsi qu'un SID identifiant la session de
connexion.
5.2.4.E - Algorithme du contrôle
d’accès Windows :
L'algorithme utilisé pour le contrôle d'accès utilise
trois éléments : le masque de permissions représentant le
type d'accès demandé, le descripteur de sécurité
représentant la protection de l'objet et le jeton du processus, contenant
les attributs d'autorisation.
L'algorithme utilise un entier de la
même taille qu'un masque de permissions (32 bits), qui sert d'accumulateur
des permissions accordées. Il est initialisé à zéro
au début de l'algorithme. Le fonctionnement de l’algorithme est le
suivant :
- le système remplit l'accumulateur avec les permissions implicites. Si
les permissions ainsi accumulées ne sont pas suffisantes, l'algorithme se
poursuit.
- Chaque entrée (ACE) de la DACL est examinée en
séquence. Si une ACE autorise certaines permissions d'accès pour
l'un des SID contenu dans le jeton, ces permissions sont accumulées.
- L'algorithme se poursuit jusqu'à ce que l'un des trois
événements suivants se produise : toutes les permissions
présentes dans le masque de permissions spécifié lors de
l'accès ont été accumulées, auquel cas
l'accès est accordé ; une ACE refusant un accès à un
SID contenu dans le jeton est rencontrée, auquel cas l'accès est
refusé ; la fin de la DACL est atteinte sans que toutes les permissions
aient été accumulées, auquel cas l'accès est
également refusé.
La première
étape permet de donner certaines permissions dites implicites. Par
exemple, nous avons vu que le propriétaire d'un objet possède
toujours les permissions de lire et de modifier la DACL de cet objet. Un autre
cas est celui d'un jeton possédant le privilège de modifier le
propriétaire de tout objet, ce qui donne implicitement la permission
correspondante sur tout objet accédé.
Dans la seconde
étape, chaque ACE est examinée et prise en compte si, d'une part,
elle concerne l'un des SID du jeton et, d'autre part, elle concerne l'une des
permissions demandées dans le masque de permissions. Toute ACE
d'interdiction interrompt le parcours et provoque un refus d'accès.
L'ordre des ACE dans une DACL est donc important, les ACE d'interdiction devant
apparaître devant les ACE d'autorisation. Le système se charge de
faire respecter cet ordre pour les ACE éditées via l'interface
graphique de l'éditeur de contrôle d'accès, tel que celui
utilisé par l'explorateur de fichiers.
5.2.4.F - Origine des descripteurs de
sécurité :
L’accès aux objets est protégé grâce
à la structure de descripteur de sécurité. Le
présent paragraphe présente le mécanisme de création
de ces descripteurs de sécurité.
Lors de l’examen de
la structure du jeton de sécurité, il a été
démontré la nécessité d’obtenir en plus des
attributs d'autorisation, des informations permettant de paramétrer la
sécurité des objets créés par le processus. Dans les
fonctions de l'API Win32 permettant de créer des objets, il est toujours
possible de passer une structure de type LPSECURITY_ATTRIBUTES, à partir
de laquelle sera construit le descripteur de sécurité du nouvel
objet. Cependant, cette approche est lourde, obligeant à spécifier
pour chaque objet des paramètres de sécurité. Il est
souvent d'usage de mettre ce paramètre à NULL : dans ce cas, le
descripteur de sécurité est construit à partir des
paramètres de sécurité trouvés dans le jeton. Ceci
permet donc de réduire le code ayant à manipuler la
sécurité des objets, tout en assurant la cohérence des
permissions sur les objets créés.
Les informations pour la
sécurité des nouveaux objets sont le propriétaire par
défaut ainsi qu'une DACL par défaut. La DACL devant être
valable pour tous les types d'objets, les permissions autorisées sont
uniquement des permissions génériques ou standard. C'est là
tout l'intérêt de disposer de permissions génériques
polymorphes : il est ainsi possible d'accorder la permission
générique de lecture à un acteur principal donné
pour tous les nouveaux objets créés, cette permission
générique étant traduite en terme de permissions standard
et spécifiques, suivant le type d'objet.
Dans le cas d'objets
stockés dans une structure hiérarchique, tels que des fichiers
contenus dans des répertoires ou des objets contenus dans des conteneurs
d'Active Directory, il existe également une fonctionnalité
d'héritage des DACL. Ceci évite par exemple d'avoir à
spécifier explicitement les DACL de fichiers contenus dans un même
répertoire. Il suffit alors de configurer la DACL sur le
répertoire et d'indiquer que les fichiers (voire les répertoires)
situés sous ce répertoire en héritent.
Dans Windows
NT 4.0, l'héritage des ACL était géré de
façon manuelle : il n'y avait pas de mécanisme automatique pour
propager les ACE héritées en cas de changement sur un objet
parent. De plus, il n'y avait pas de distinction entre une ACE
héritée et une ACE propre à l'objet. Ce modèle
d'héritage n'était donc pas très flexible en
pratique.
Dans Windows 2000, le modèle d'héritage a
été étendu, notamment à cause de l'importance de
l'héritage pour les objets contenus dans l'annuaire Active Directory.
Dans ce nouveau modèle, l'héritage est dynamique, de sorte que
lorsque les permissions sont modifiées sur un objet parent, il y a
propagation automatique aux objets contenus. De plus, les ACE
héritées sont marquées comme telles, afin de les distinguer
des ACE propres à un objet. Il devient ainsi possible d'utiliser
l'héritage pour gérer de façon globale des permissions,
tout en gardant la possibilité d'écraser, de façon locale,
certaines permissions. Du coup, les ACE héritées doivent
apparaître après les ACE propres à un objet, afin qu'il soit
possible de redéfinir des permissions par rapport à celles
héritées.
5.2.4.G - Les privilèges sous
Windows :
Les privilèges permettent une autre forme d'autorisation que le
contrôle d'accès. En effet, le contrôle d'accès n'est
pas adapté à toutes les situations.
L'exemple typique dans
lequel un privilège est plus adapté que le contrôle
d'accès consiste à étudier les privilèges de
sauvegarde et de restauration de fichiers. Lorsqu'ils sont donnés
à un acteur principal, ils permettent de lire et écrire tous
fichiers du système, en contournant les mécanismes de
contrôle d'accès. L'intérêt d'utiliser un
privilège pour autoriser ce genre de tâche est double. En premier
lieu, il évite d'avoir à autoriser les opérateurs de
sauvegarde à lire ou écrire tous les fichiers du système.
Cette technique obligerait à modifier la liste de contrôle
d'accès de chaque fichier. En second lieu, il ne rend possible la lecture
et l'écriture de fichiers que dans le cadre d'opérations de
sauvegarde. En effet, pour pouvoir sauvegarder ou restaurer un fichier, il faut
activer ce privilège et ouvrir le fichier à sauvegarder ou
restaurer avec un drapeau spécial.
Les privilèges sont
également utilisés lorsque le contrôle d'accès n'est
pas possible, aucun objet n'ayant été défini pour autoriser
ce que le privilège permet. Par exemple, il existe des privilèges
permettant d'arrêter le système ou d'en changer l'heure,
l'hypothétique objet de type SYSTEM, sur lequel il serait possible de
définir les permissions d'arrêt et de changement d'heure,
n'existant pas.
Les privilèges sont des attributs d'autorisation
locaux et n'ont donc de sens que sur le système local. Ils sont
affectés à des principaux par l'administrateur du système,
pour lequel ils sont connus sous le nom de droits utilisateurs. Les
privilèges se retrouvent dans les jetons des processus mais ne sont, pour
la plupart, pas activés. Ils doivent donc être explicitement
activés avant de pouvoir être utilisés. Un programme
correctement écrit n'active les privilèges nécessaires que
le temps d'exécuter une action privilégiée.